﻿// // ******************************************************************
// //       /\ /|       @file       TesseractHelper.cs
// //       \ V/        @brief      await29
// //       | "")       @author     Await, 285283010@qq.com
// //       /  |
// //      /  \\        @Modified   2025-01-09 20:01
// //    *(__\_\        @Copyright  Copyright (c) , 2025-01-05 13:01 Await
// // ******************************************************************

using Tesseract;
using SkiaSharp;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;

namespace AutomaticSubtitles.Service.Infrastructure.Helper;

public class TesseractHelper
{
    private const string BaseUrl = "https://github.com/tesseract-ocr/tessdata/raw/main";

    private static List<string>? _languageList;
    public static string? TessDataPath;


    private static readonly HttpClient client = new();


    public static async Task<List<string>?> GetAllTessData()
    {
        try
        {
            using var client = new HttpClient();
            client.BaseAddress = new Uri("https://api.github.com");
            client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0");

            var response = await client.GetAsync("/repos/tesseract-ocr/tessdata/contents/");
            var content = await response.Content.ReadAsStringAsync();

            // 解析JSON响应
            using var document = JsonDocument.Parse(content);
            var files = document.RootElement.EnumerateArray()
                .Where(x => x.GetProperty("name").GetString().EndsWith(".traineddata"))
                .Select(x => x.GetProperty("name").GetString().Replace(".traineddata", ""))
                .OrderBy(x => x).ToList();

            Console.WriteLine("可用的语言代码：");
            foreach (var lang in files) Console.WriteLine($"- {lang}");
            return files.ToList();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取语言列表失败: {ex.Message}");
        }

        return null;
    }

    public static async Task DownloadTessDataAsync(string language)
    {
        try
        {
            Directory.CreateDirectory(TessDataPath);

            var fileName = $"{language}.traineddata";
            var filePath = Path.Combine(TessDataPath, fileName);

            // 如果文件已存在，跳过下载
            if (File.Exists(filePath))
            {
                Console.WriteLine($"{fileName} 已存在，跳过下载。");
                return;
            }

            var url = $"{BaseUrl}/{fileName}";
            Console.WriteLine($"开始下载 {fileName}...");

            var data = await client.GetByteArrayAsync(url);
            await File.WriteAllBytesAsync(filePath, data);

            Console.WriteLine($"{fileName} 下载完成！");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"下载失败: {ex.Message}");
            throw;
        }
    }

    public static async Task DownloadAllTessDataAsync()
    {
        _languageList ??= await GetAllTessData();
        if (_languageList == null) return;
        foreach (var lang in _languageList) await DownloadTessDataAsync(lang);
    }

    public static async Task<string> LanguageConvert(string language)
    {
        _languageList ??= await GetAllTessData();
        if (_languageList == null) return "chi_sim";
        return _languageList.FirstOrDefault(x => x.StartsWith(language)) ?? "chi_sim";
    }

    public static async Task ConvertSupToSrt(string language, string supFilePath, string outputSrtPath)
        // public async Task ConvertSupToSrt(string supPath, string outputPath, int maxDegreeOfParallelism = 4)
    {
        //语言转换
        var languageCode = await LanguageConvert(language);
        try
        {
            using var reader = new SupReaderHelper(supFilePath);
            var results = new ConcurrentDictionary<int, (int Index, string Text, TimeSpan Start, TimeSpan End)>();

            // var tasks = new List<Task>();

            // await foreach (var frame in reader.ReadFramesAsync())
            await foreach (var frame in reader.ReadFilePngFramesAsync())
                // tasks.Add(Task.Run(() =>
                // {
                try
                {
                    if (!File.Exists(frame)) return;
                    using var engine = new TesseractEngine(TessDataPath, languageCode, EngineMode.Default);
                    // 配置OCR参数
                    engine.SetVariable("tessedit_char_whitelist", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?-'\"()[]{}:; ");

                    using (var img = Pix.LoadFromFile(frame))
                    {
                        if (img == null) return;
                        var result = engine.Process(img);
                        var text = result.GetText();
                        if (!text.IsNullOrWhiteSpace())
                        {
                            Console.WriteLine($"图片数据: {text}");
                        }
                    }
                    // // 将ImageSharp图像转换为Tesseract可用的格式
                    // using var bitmap = ConvertRgba32ToPix(frame.Image);
                    // using var page = engine.Process(bitmap);
                    //
                    // var text = page.GetText().Trim();
                    // if (!string.IsNullOrWhiteSpace(text))
                    //     results.TryAdd(frame.Index - 1, (
                    //         frame.Index,
                    //         text,
                    //         frame.StartTime,
                    //         frame.EndTime
                    //     ));
                }
                catch (Exception ex)
                {
                    // Console.WriteLine($"处理帧 {frame.Index} 失败: {ex.Message}");
                }
                finally
                {
                    // frame.Dispose();
                }
            // }));

            // await Task.WhenAll(tasks);

            // 生成SRT文件
            if (results != null && results.Count > 0)
                await GenerateSrtFile(results, outputSrtPath);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"转换失败: {ex.Message}");
        }
    }

    private static async Task GenerateSrtFile(ConcurrentDictionary<int, (int Index, string Text, TimeSpan Start, TimeSpan End)> results, string outputPath)
    {
        var srtBuilder = new StringBuilder();
        foreach (var entry in results.OrderBy(x => x.Key))
        {
            var (index, text, start, end) = entry.Value;
            srtBuilder.AppendLine(index.ToString());
            srtBuilder.AppendLine($"{FormatTimestamp(start)} --> {FormatTimestamp(end)}");
            srtBuilder.AppendLine(text);
            srtBuilder.AppendLine();
        }

        await File.WriteAllTextAsync(outputPath, srtBuilder.ToString(), Encoding.UTF8);
    }

    public static Pix ConvertRgba32ToPix(Image<Rgba32> image)
    {
        // 将 ImageSharp 图像保存为 BMP 格式的 MemoryStream
        using (var memoryStream = new MemoryStream())
        {
            image.SaveAsBmp(memoryStream);
            memoryStream.Position = 0;
            // 从 MemoryStream 创建 Pix
            return Pix.LoadFromMemory(memoryStream.ToArray());
        }
    }

    // public static async Task ConvertSupToSrt(string language, string supFilePath, string outputSrtPath)
    // {
    //     //语言转换
    //     var languageCode = await LanguageConvert(language);
    //
    //     try
    //     {
    //         // 确保tessdata路径存在
    //         if (!Directory.Exists(TessDataPath)) throw new DirectoryNotFoundException($"找不到tessdata目录: {TessDataPath}");
    //
    //         // 1. 读取SUP文件
    //         var supReader = new SupReaderHelper(supFilePath);
    //         var frames = supReader.ReadFramesParallelAsync();
    //         // 初始化Tesseract引擎
    //         using var engine = new TesseractEngine(TessDataPath, languageCode, EngineMode.Default);
    //         // 3. 配置OCR参数
    //         engine.SetVariable("tessedit_char_whitelist", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?-'\"()[]{}:; ");
    //         // 设置OCR参数
    //         engine.SetVariable("preserve_interword_spaces", "1");
    //
    //         Console.WriteLine("开始读取SUP文件...");
    //         var supFrames = ReadSupFile(supFilePath);
    //         Console.WriteLine($"成功读取 {supFrames.Count} 帧字幕");
    //
    //         // 4. 准备SRT输出
    //         var srtBuilder = new StringBuilder();
    //         var subtitleIndex = 1;
    //         // 5. 处理每一帧
    //         foreach (var frame in frames)
    //             using (var bitmap = frame.ToBitmap()) // 将SUP帧转换为Bitmap
    //             using (var page = engine.Process(bitmap))
    //             {
    //                 var text = page.GetText().Trim();
    //                 // 如果识别出文本
    //                 if (string.IsNullOrWhiteSpace(text)) continue;
    //                 // 格式化SRT
    //                 srtBuilder.AppendLine(subtitleIndex.ToString());
    //                 srtBuilder.AppendLine($"{FormatTimestamp(frame.StartTime)} --> {FormatTimestamp(frame.EndTime)}");
    //                 srtBuilder.AppendLine(text);
    //                 srtBuilder.AppendLine();
    //
    //                 subtitleIndex++;
    //             }
    //
    //         // 6. 保存SRT文件
    //         await File.WriteAllTextAsync(outputSrtPath, srtBuilder.ToString(), Encoding.UTF8);
    //
    //         // using var writer = new StreamWriter(outputSrtPath, false, Encoding.UTF8);
    //         // var subtitleIndex = 1;
    //         //
    //         // foreach (var frame in supFrames)
    //         //     try
    //         //     {
    //         //         // 使用SkiaSharp处理图像
    //         //         using var skBitmap = SKBitmap.Decode(frame.ImageData);
    //         //         using var skImage = SKImage.FromBitmap(skBitmap);
    //         //
    //         //         // 将图像转换为Tesseract可识别的格式
    //         //         using var pixData = ConvertSkiaToLeptonica(skBitmap);
    //         //         using var page = engine.Process(pixData);
    //         //         var text = page.GetText().Trim();
    //         //
    //         //         if (string.IsNullOrEmpty(text)) continue;
    //         //         // 写入srt格式
    //         //         writer.WriteLine(subtitleIndex);
    //         //         writer.WriteLine($"{FormatTime(frame.StartTime)} --> {FormatTime(frame.EndTime)}");
    //         //         writer.WriteLine(text);
    //         //         writer.WriteLine();
    //         //
    //         //         Console.WriteLine($"处理第 {subtitleIndex} 帧字幕");
    //         //         subtitleIndex++;
    //         //     }
    //         //     catch (Exception ex)
    //         //     {
    //         //         Console.WriteLine($"处理帧 {subtitleIndex} 时发生错误: {ex.Message}");
    //         //     }
    //
    //         Console.WriteLine("转换完成！");
    //     }
    //     catch (Exception ex)
    //     {
    //         Console.WriteLine($"转换过程中发生错误: {ex.Message}");
    //         throw;
    //     }
    // }

    private static string FormatTimestamp(TimeSpan time)
    {
        return $"{(int)time.TotalHours:00}:{time.Minutes:00}:{time.Seconds:00},{time.Milliseconds:000}";
    }

    private static Pix ConvertSkiaToLeptonica(SKBitmap skBitmap)
    {
        // 预处理图像以提高OCR质量
        using var processedBitmap = new SKBitmap(skBitmap.Width, skBitmap.Height);
        using (var canvas = new SKCanvas(processedBitmap))
        {
            // 清除背景
            canvas.Clear(SKColors.White);

            // 应用图像处理
            using var paint = new SKPaint
            {
                ColorFilter = SKColorFilter.CreateColorMatrix(new float[]
                {
                    2.0f, 0, 0, 0, -255,
                    0, 2.0f, 0, 0, -255,
                    0, 0, 2.0f, 0, -255,
                    0, 0, 0, 1.0f, 0
                })
            };

            canvas.DrawBitmap(skBitmap, 0, 0, paint);
        }

        // 转换为Pix
        using var image = SKImage.FromBitmap(processedBitmap);
        using var data = image.Encode(SKEncodedImageFormat.Png, 100);
        var buffer = data.ToArray();

        return Pix.LoadFromMemory(buffer);
    }

    private static Pix ConvertSkiaToLeptonica2(SKBitmap skBitmap)
    {
        // 将图像保存为临时PNG文件
        using var image = SKImage.FromBitmap(skBitmap);
        using var data = image.Encode(SKEncodedImageFormat.Png, 100);
        var buffer = data.ToArray();
        // 使用 Pix.LoadFromMemory 直接从内存创建 Pix
        return Pix.LoadFromMemory(buffer);
    }

    private static string FormatTime(TimeSpan time)
    {
        return $"{time.Hours:D2}:{time.Minutes:D2}:{time.Seconds:D2},{time.Milliseconds:D3}";
    }

    private static List<SubtitleFrame> ReadSupFile(string supFilePath)
    {
        var frames = new List<SubtitleFrame>();

        try
        {
            using var fileStream = new FileStream(supFilePath, FileMode.Open, FileAccess.Read);
            using var reader = new BinaryReader(fileStream);

            while (reader.BaseStream.Position < reader.BaseStream.Length)
            {
                // 读取PGS字幕头部
                var header = reader.ReadBytes(13);

                // 验证PGS魔数
                if (header[0] != 0x50 || header[1] != 0x47) // "PG"
                    // throw new Exception("无效的SUP文件格式");
                    continue;

                // 解析时间戳 (通常在字节 2-5 和 6-9)
                var startTime = BitConverter.ToUInt32(header, 2);
                var endTime = BitConverter.ToUInt32(header, 6);

                // 读取数据大小 (通常在字节 10-13)
                var dataSize = BitConverter.ToInt32(header.Skip(10).Take(3).Concat(new byte[] { 0 }).ToArray(), 0);

                // 读取图像数据
                var imageData = reader.ReadBytes(dataSize);

                frames.Add(new SubtitleFrame
                {
                    StartTime = TimeSpan.FromMilliseconds(startTime),
                    EndTime = TimeSpan.FromMilliseconds(endTime),
                    ImageData = imageData
                });
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"读取SUP文件时发生错误: {ex.Message}");
            throw;
        }

        return frames;
    }
}

public class SubtitleFrame
{
    public TimeSpan StartTime { get; set; }
    public TimeSpan EndTime   { get; set; }
    public byte[]   ImageData { get; set; }
}